<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="MapStruct使用指南, 码道诚公">
    <meta name="description" content="">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="baidu-site-verification" content="code-oqVlgh2wQV" />
    <meta name="google-site-verification" content="Z-8Fm46WY6NL_3kxilmoqToW4jnvyF7boTgciTLBXUs" />
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>MapStruct使用指南 | 码道诚公</title>
    <link rel="icon" type="image/png" href="/favicon.png">

    <link rel="stylesheet" type="text/css" href="/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/css/my.css">

    <script src="/libs/jquery/jquery.min.js"></script>

<meta name="generator" content="Hexo 5.2.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
<link rel="alternate" href="/atom.xml" title="码道诚公" type="application/atom+xml">
<link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head>




<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/" class="waves-effect waves-light">
                    
                    <img src="/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">码道诚公</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>留言板</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">码道诚公</div>
        <div class="logo-desc">
            
            Never really desperate, only the lost of the soul.
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			留言板
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
    </ul>
</div>


        </div>

        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/medias/featureimages/2.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">MapStruct使用指南</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        margin: 35px 0 15px 0;
        padding-left: 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        height: calc(100vh - 250px);
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/tags/Java/">
                                <span class="chip bg-color">Java</span>
                            </a>
                        
                            <a href="/tags/%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7/">
                                <span class="chip bg-color">效率工具</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/categories/Java/" class="post-category">
                                Java
                            </a>
                        
                            <a href="/categories/Java/%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7/" class="post-category">
                                效率工具
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2021-04-30
                </div>
                

                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    7.7k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>阅读时长:&nbsp;&nbsp;
                    32 分
                </div>
                

                
            </div>
        </div>
        <hr class="clearfix">
        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h1><p>随着微服务和分布式应用程序迅速占领开发领域，数据完整性和安全性比以往任何时候都更加重要。在这些松散耦合的系统之间，安全的通信渠道和有限的数据传输是最重要的。大多数时候，终端用户或服务不需要访问模型中的全部数据，而只需要访问某些特定的部分。</p>
<p>数据传输对象(Data Transfer Objects, DTO)经常被用于这些应用中。DTO只是持有另一个对象中被请求的信息的对象。通常情况下，这些信息是有限的一部分。例如，在持久化层定义的实体和发往客户端的DTO之间经常会出现相互之间的转换。由于DTO是原始对象的反映，因此这些类之间的映射器在转换过程中扮演着关键角色。</p>
<p>这就是MapStruct解决的问题：手动创建bean映射器非常耗时。 但是该库可以自动生成Bean映射器类。</p>
<p>在本文中，我们将深入研究<a target="_blank" rel="noopener" href="https://mapstruct.org/">MapStruct</a>。</p>
<h2 id="MapStruct"><a href="#MapStruct" class="headerlink" title="MapStruct"></a>MapStruct</h2><p>MapStruct是一个开源的基于Java的代码生成器，用于创建实现Java Bean之间转换的扩展映射器。使用MapStruct，我们只需要创建接口，而该库会通过注解在编译过程中自动创建具体的映射实现，大大减少了通常需要手工编写的样板代码的数量。</p>
<h3 id="MapStruct-依赖"><a href="#MapStruct-依赖" class="headerlink" title="MapStruct 依赖"></a>MapStruct 依赖</h3><p>如果你使用Maven的话，可以通过引入依赖安装MapStruct：</p>
<pre class=" language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencies</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">></span></span>org.mapstruct<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">></span></span>mapstruct<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">></span></span>${org.mapstruct.version}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencies</span><span class="token punctuation">></span></span></code></pre>
<p>这个依赖项会导入MapStruct的核心注释。由于MapStruct在编译时工作，并且会集成到像Maven和Gradle这样的构建工具上，我们还必须在&lt;build中/&gt;标签中添加一个插件<code>maven-compiler-plugin</code>，并在其配置中添加<code>annotationProcessorPaths</code>，该插件会在构建时生成对应的代码。</p>
<pre class=" language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>build</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plugins</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plugin</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">></span></span>org.apache.maven.plugins<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">></span></span>maven-compiler-plugin<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">></span></span>3.5.1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>configuration</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span><span class="token punctuation">></span></span>1.8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>source</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span><span class="token punctuation">></span></span>1.8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>target</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>annotationProcessorPaths</span><span class="token punctuation">></span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>path</span><span class="token punctuation">></span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">></span></span>org.mapstruct<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">></span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">></span></span>mapstruct-processor<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">></span></span>
                        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">></span></span>${org.mapstruct.version}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">></span></span>
                    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>path</span><span class="token punctuation">></span></span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>annotationProcessorPaths</span><span class="token punctuation">></span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>configuration</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plugin</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plugins</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>build</span><span class="token punctuation">></span></span></code></pre>
<p>如果你使用Gradle的话，安装MapStruct会更简单：</p>
<pre class=" language-groovy"><code class="language-groovy">plugins <span class="token punctuation">{</span>
    id <span class="token string">'net.ltgt.apt'</span> version <span class="token string">'0.20'</span>
<span class="token punctuation">}</span>

apply plugin<span class="token punctuation">:</span> <span class="token string">'net.ltgt.apt-idea'</span>
apply plugin<span class="token punctuation">:</span> <span class="token string">'net.ltgt.apt-eclipse'</span>

dependencies <span class="token punctuation">{</span>
    compile <span class="token string">"org.mapstruct:mapstruct:${mapstructVersion}"</span>
    annotationProcessor <span class="token string">"org.mapstruct:mapstruct-processor:${mapstructVersion}"</span>
<span class="token punctuation">}</span></code></pre>
<p><code>net.ltgt.apt</code>插件会负责处理注释。你可以根据你使用的IDE启用插件<code>apt-idea</code>或<code>apt-eclipse</code>插件。</p>
<p><a target="_blank" rel="noopener" href="https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.mapstruct%22%20AND%20a%3A%22mapstruct%22">MapStruct</a>及其<a target="_blank" rel="noopener" href="https://search.maven.org/classic/#search|ga|1|g%3A%22org.mapstruct%22%20AND%20a%3A%22mapstruct-processor%22">处理器</a>的最新稳定版本都可以从<a target="_blank" rel="noopener" href="https://search.maven.org/search?q=g:org.mapstruct">Maven中央仓库</a>中获得。</p>
<h1 id="映射"><a href="#映射" class="headerlink" title="映射"></a>映射</h1><h2 id="基本映射"><a href="#基本映射" class="headerlink" title="基本映射"></a>基本映射</h2><p>我们先从一些基本的映射开始。我们会创建一个Doctor对象和一个DoctorDto。为了方便起见，它们的属性字段都使用相同的名称：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Doctor</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorDto</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>现在，为了在这两者之间进行映射，我们要创建一个<code>DoctorMapper</code>接口。对该接口使用<code>@Mapper</code>注解，MapStruct就会知道这是两个类之间的映射器。</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
    DoctorMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>这段代码中创建了一个<code>DoctorMapper</code>类型的实例<code>INSTANCE</code>，在生成对应的实现代码后，这就是我们调用的“入口”。</p>
<p>我们在接口中定义了<code>toDto()</code>方法，该方法接收一个<code>Doctor</code>实例为参数，并返回一个<code>DoctorDto</code>实例。这足以让MapStruct知道我们想把一个<code>Doctor</code>实例映射到一个<code>DoctorDto</code>实例。</p>
<p>当我们构建/编译应用程序时，MapStruct注解处理器插件会识别出DoctorMapper接口并为其生成一个实现类。</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> doctor <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        DoctorDtoBuilder doctorDto <span class="token operator">=</span> DoctorDto<span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        doctorDto<span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> doctorDto<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><code>DoctorMapperImpl</code>类中包含一个<code>toDto()</code>方法，将我们的<code>Doctor</code>属性值映射到<code>DoctorDto</code>的属性字段中。如果要将<code>Doctor</code>实例映射到一个<code>DoctorDto</code>实例，可以这样写：</p>
<pre class=" language-java"><code class="language-java">DoctorDto doctorDto <span class="token operator">=</span> DoctorMapper<span class="token punctuation">.</span>INSTANCE<span class="token punctuation">.</span><span class="token function">toDto</span><span class="token punctuation">(</span>doctor<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><strong>注意</strong>：你可能也注意到了上面实现代码中的<code>DoctorDtoBuilder</code>。因为builder代码往往比较长，为了简洁起见，这里省略了builder模式的实现代码。如果你的类中包含Builder，MapStruct会尝试使用它来创建实例；如果没有的话，MapStruct将通过<code>new</code>关键字进行实例化。</p>
<h2 id="不同字段间映射"><a href="#不同字段间映射" class="headerlink" title="不同字段间映射"></a>不同字段间映射</h2><p>通常，模型和DTO的字段名不会完全相同。由于团队成员各自指定命名，以及针对不同的调用服务，开发者对返回信息的打包方式选择不同，名称可能会有轻微的变化。</p>
<p>MapStruct通过<code>@Mapping</code>注解对这类情况提供了支持。</p>
<h3 id="不同属性名称"><a href="#不同属性名称" class="headerlink" title="不同属性名称"></a>不同属性名称</h3><p>我们先更新<code>Doctor</code>类，添加一个属性<code>specialty</code>：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Doctor</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String specialty<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>在<code>DoctorDto</code>类中添加一个<code>specialization</code>属性：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorDto</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String specialization<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>现在，我们需要让 <code>DoctorMapper</code> 知道这里的不一致。我们可以使用 <code>@Mapping</code> 注解，并设置其内部的 <code>source</code> 和 <code>target</code> 标记分别指向不一致的两个字段。</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
    DoctorMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.specialty"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialization"</span><span class="token punctuation">)</span>
    DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>这个注解代码的含义是：<code>Doctor</code>中的<code>specialty</code>字段对应于<code>DoctorDto</code>类的 <code>specialization</code> 。</p>
<p>编译之后，会生成如下实现代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctor <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        DoctorDtoBuilder doctorDto <span class="token operator">=</span> DoctorDto<span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        doctorDto<span class="token punctuation">.</span><span class="token function">specialization</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getSpecialty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> doctorDto<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="多个源类"><a href="#多个源类" class="headerlink" title="多个源类"></a>多个源类</h3><p>有时，单个类不足以构建DTO，我们可能希望将多个类中的值聚合为一个DTO，供终端用户使用。这也可以通过在<code>@Mapping</code>注解中设置适当的标志来完成。</p>
<p>我们先新建另一个对象 <code>Education</code>:</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Education</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> String degreeName<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String institute<span class="token punctuation">;</span>
    <span class="token keyword">private</span> Integer yearOfPassing<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>然后向 <code>DoctorDto</code>中添加一个新的字段：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorDto</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String degree<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String specialization<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>接下来，将 <code>DoctorMapper</code> 接口更新为如下代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
    DoctorMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.specialty"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialization"</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"education.degreeName"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"degree"</span><span class="token punctuation">)</span>
    DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">,</span> Education education<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>我们添加了另一个<code>@Mapping</code>注解，并将其<code>source</code>设置为<code>Education</code>类的<code>degreeName</code>，将<code>target</code>设置为<code>DoctorDto</code>类的<code>degree</code>字段。</p>
<p>如果 <code>Education</code> 类和 <code>Doctor</code> 类包含同名的字段，我们必须让映射器知道使用哪一个，否则它会抛出一个异常。举例来说，如果两个模型都包含一个<code>id</code>字段，我们就要选择将哪个类中的<code>id</code>映射到DTO属性中。</p>
<h2 id="子对象映射"><a href="#子对象映射" class="headerlink" title="子对象映射"></a>子对象映射</h2><p>多数情况下，POJO中不会<em>只</em>包含基本数据类型，其中往往会包含其它类。比如说，一个<code>Doctor</code>类中会有多个患者类：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Patient</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>在Doctor中添加一个患者列表<code>List</code>：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Doctor</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String specialty<span class="token punctuation">;</span>
    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>Patient<span class="token operator">></span> patientList<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>因为<code>Patient</code>需要转换，为其创建一个对应的DTO：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PatientDto</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>最后，在 <code>DoctorDto</code> 中新增一个存储 <code>PatientDto</code>的列表：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorDto</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String degree<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String specialization<span class="token punctuation">;</span>
    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>PatientDto<span class="token operator">></span> patientDtoList<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>在修改 <code>DoctorMapper</code>之前，我们先创建一个支持 <code>Patient</code> 和 <code>PatientDto</code> 转换的映射器接口：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">PatientMapper</span> <span class="token punctuation">{</span>
    PatientMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    PatientDto <span class="token function">toDto</span><span class="token punctuation">(</span>Patient patient<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>这是一个基本映射器，只会处理几个基本数据类型。</p>
<p>然后，我们再来修改 <code>DoctorMapper</code> 处理一下患者列表：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    DoctorMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.patientList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientDtoList"</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.specialty"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialization"</span><span class="token punctuation">)</span>
    DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>因为我们要处理另一个需要映射的类，所以这里设置了<code>@Mapper</code>注解的<code>uses</code>标志，这样现在的 <code>@Mapper</code> 就可以使用另一个 <code>@Mapper</code>映射器。我们这里只加了一个，但你想在这里添加多少class/mapper都可以。</p>
<p>我们已经添加了<code>uses</code>标志，所以在为<code>DoctorMapper</code>接口生成映射器实现时，MapStruct 也会把 <code>Patient</code> 模型转换成 <code>PatientDto</code> ——因为我们已经为这个任务注册了 <code>PatientMapper</code>。</p>
<p>编译查看最新想实现代码：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> PatientMapper patientMapper <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span> PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> doctor <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        DoctorDtoBuilder doctorDto <span class="token operator">=</span> DoctorDto<span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        doctorDto<span class="token punctuation">.</span><span class="token function">patientDtoList</span><span class="token punctuation">(</span> <span class="token function">patientListToPatientDtoList</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">specialization</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getSpecialty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> doctorDto<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">protected</span> List<span class="token operator">&lt;</span>PatientDto<span class="token operator">></span> <span class="token function">patientListToPatientDtoList</span><span class="token punctuation">(</span>List<span class="token operator">&lt;</span>Patient<span class="token operator">></span> list<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> list <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        List<span class="token operator">&lt;</span>PatientDto<span class="token operator">></span> list1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span>PatientDto<span class="token operator">></span><span class="token punctuation">(</span> list<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span> Patient patient <span class="token operator">:</span> list <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            list1<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span> patientMapper<span class="token punctuation">.</span><span class="token function">toDto</span><span class="token punctuation">(</span> patient <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> list1<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>显然，除了<code>toDto()</code>映射方法外，最终实现中还添加了一个新的映射方法——<code> patientListToPatientDtoList()</code>。这个方法是在没有显式定义的情况下添加的，只是因为我们把<code>PatientMapper</code>添加到了<code>DoctorMapper</code>中。</p>
<p>该方法会遍历一个<code>Patient</code>列表，将每个元素转换为<code>PatientDto</code>，并将转换后的对象添加到<code>DoctorDto</code>对象内中的列表中。</p>
<h2 id="更新现有实例"><a href="#更新现有实例" class="headerlink" title="更新现有实例"></a>更新现有实例</h2><p>有时，我们希望用DTO的最新值更新一个模型中的属性，对目标对象(我们的例子中是<code>DoctorDto</code>)使用<code>@MappingTarget</code>注解，就可以更新现有的实例.</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    DoctorMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.patientDtoList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientList"</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.specialization"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialty"</span><span class="token punctuation">)</span>
    <span class="token keyword">void</span> <span class="token function">updateModel</span><span class="token punctuation">(</span>DoctorDto doctorDto<span class="token punctuation">,</span> <span class="token annotation punctuation">@MappingTarget</span> Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>重新生成实现代码，就可以得到<code>updateModel()</code>方法：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">updateModel</span><span class="token punctuation">(</span>DoctorDto doctorDto<span class="token punctuation">,</span> Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctorDto <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            List<span class="token operator">&lt;</span>Patient<span class="token operator">></span> list <span class="token operator">=</span> <span class="token function">patientDtoListToPatientList</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getPatientDtoList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>list <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addAll</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">else</span> <span class="token punctuation">{</span>
                doctor<span class="token punctuation">.</span><span class="token function">setPatientList</span><span class="token punctuation">(</span>null<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span> <span class="token punctuation">{</span>
            List<span class="token operator">&lt;</span>Patient<span class="token operator">></span> list <span class="token operator">=</span> <span class="token function">patientDtoListToPatientList</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getPatientDtoList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>list <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                doctor<span class="token punctuation">.</span><span class="token function">setPatientList</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        doctor<span class="token punctuation">.</span><span class="token function">setSpecialty</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getSpecialization</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctor<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctor<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>值得注意的是，由于患者列表是该模型中的子实体，因此患者列表也会进行更新。</p>
<h1 id="数据类型转换"><a href="#数据类型转换" class="headerlink" title="数据类型转换"></a>数据类型转换</h1><h2 id="数据类型映射"><a href="#数据类型映射" class="headerlink" title="数据类型映射"></a>数据类型映射</h2><p>MapStruct支持<code>source</code>和<code>target</code>属性之间的数据类型转换。它还提供了基本类型及其相应的包装类之间的自动转换。</p>
<p>自动类型转换适用于：</p>
<ul>
<li>基本类型及其对应的包装类之间。比如， <code>int</code> 和 <code>Integer</code>， <code>float</code> 和 <code>Float</code>， <code>long</code> 和 <code>Long</code>，<code>boolean</code> 和 <code>Boolean</code> 等。</li>
<li>任意基本类型与任意包装类之间。如 <code>int</code> 和 <code>long</code>， <code>byte</code> 和 <code>Integer</code> 等。</li>
<li>所有基本类型及包装类与<code>String</code>之间。如 <code>boolean</code> 和 <code>String</code>， <code>Integer</code> 和 <code>String</code>， <code>float</code> 和 <code>String</code> 等。</li>
<li>枚举和<code>String</code>之间。</li>
<li>Java大数类型(<code>java.math.BigInteger</code>， <code>java.math.BigDecimal</code>) 和Java基本类型(包括其包装类)与<code>String</code>之间。</li>
<li>其它情况详见<a target="_blank" rel="noopener" href="https://mapstruct.org/documentation/stable/reference/html/#implicit-type-conversions">MapStruct官方文档</a>。</li>
</ul>
<p>因此，在生成映射器代码的过程中，如果源字段和目标字段之间属于上述任何一种情况，则MapStrcut会自行处理类型转换。</p>
<p>我们修改 <code>PatientDto</code> ，新增一个 <code>dateofBirth</code>字段：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PatientDto</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> LocalDate dateOfBirth<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>另一方面，加入 <code>Patient</code> 对象中有一个<code>String</code> 类型的 <code>dateOfBirth</code> ：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Patient</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String dateOfBirth<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>在两者之间创建一个映射器：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">PatientMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> dateFormat <span class="token operator">=</span> <span class="token string">"dd/MMM/yyyy"</span><span class="token punctuation">)</span>
    Patient <span class="token function">toModel</span><span class="token punctuation">(</span>PatientDto patientDto<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>当对日期进行转换时，我们也可以使用 <code>dateFormat</code> 设置格式声明。生成的实现代码形式大致如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PatientMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">PatientMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> Patient <span class="token function">toModel</span><span class="token punctuation">(</span>PatientDto patientDto<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>patientDto <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        PatientBuilder patient <span class="token operator">=</span> Patient<span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>patientDto<span class="token punctuation">.</span><span class="token function">getDateOfBirth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            patient<span class="token punctuation">.</span><span class="token function">dateOfBirth</span><span class="token punctuation">(</span>DateTimeFormatter<span class="token punctuation">.</span><span class="token function">ofPattern</span><span class="token punctuation">(</span><span class="token string">"dd/MMM/yyyy"</span><span class="token punctuation">)</span>
                                <span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>patientDto<span class="token punctuation">.</span><span class="token function">getDateOfBirth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        patient<span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span>patientDto<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        patient<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span>patientDto<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> patient<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到，这里使用了 <code>dateFormat</code> 声明的日期格式。如果我们没有声明格式的话，MapStruct会使用 <code>LocalDate</code>的默认格式，大致如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">if</span> <span class="token punctuation">(</span>patientDto<span class="token punctuation">.</span><span class="token function">getDateOfBirth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    patient<span class="token punctuation">.</span><span class="token function">dateOfBirth</span><span class="token punctuation">(</span>DateTimeFormatter<span class="token punctuation">.</span>ISO_LOCAL_DATE
                        <span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>patientDto<span class="token punctuation">.</span><span class="token function">getDateOfBirth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="数字格式转换"><a href="#数字格式转换" class="headerlink" title="数字格式转换"></a>数字格式转换</h3><p>上面的例子中可以看到，在进行日期转换的时候，可以通过<code>dateFormat</code>标志指定日期的格式。</p>
<p>除此之外，对于数字的转换，也可以使用<code>numberFormat</code>指定显示格式：</p>
<pre class=" language-java"><code class="language-java">   <span class="token comment" spellcheck="true">// 数字格式转换示例</span>
   <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"price"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"price"</span><span class="token punctuation">,</span> numberFormat <span class="token operator">=</span> <span class="token string">"$#.00"</span><span class="token punctuation">)</span></code></pre>
<h2 id="枚举映射"><a href="#枚举映射" class="headerlink" title="枚举映射"></a>枚举映射</h2><p>枚举映射的工作方式与字段映射相同。MapStruct会对具有相同名称的枚举进行映射，这一点没有问题。但是，对于具有不同名称的枚举项，我们需要使用<code>@ValueMapping</code>注解。同样，这与普通类型的<code>@Mapping</code>注解也相似。</p>
<p>我们先创建两个枚举。第一个是 <code>PaymentType</code>:</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">enum</span> PaymentType <span class="token punctuation">{</span>
    CASH<span class="token punctuation">,</span>
    CHEQUE<span class="token punctuation">,</span>
    CARD_VISA<span class="token punctuation">,</span>
    CARD_MASTER<span class="token punctuation">,</span>
    CARD_CREDIT
<span class="token punctuation">}</span></code></pre>
<p>比如说，这是一个应用内可用的支付方式，现在我们要根据这些选项创建一个更一般、有限的识图：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">enum</span> PaymentTypeView <span class="token punctuation">{</span>    CASH<span class="token punctuation">,</span>    CHEQUE<span class="token punctuation">,</span>    CARD<span class="token punctuation">}</span></code></pre>
<p>现在，我们创建这两个<code>enum</code>之间的映射器接口：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">PaymentTypeMapper</span> <span class="token punctuation">{</span>

    PaymentTypeMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>PaymentTypeMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@ValueMappings</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            <span class="token annotation punctuation">@ValueMapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"CARD_VISA"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"CARD"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token annotation punctuation">@ValueMapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"CARD_MASTER"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"CARD"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token annotation punctuation">@ValueMapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"CARD_CREDIT"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"CARD"</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    PaymentTypeView <span class="token function">paymentTypeToPaymentTypeView</span><span class="token punctuation">(</span>PaymentType paymentType<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>这个例子中，我们设置了一般性的<code>CARD</code>值，和更具体的 <code>CARD_VISA</code>, <code>CARD_MASTER</code> 和 <code>CARD_CREDIT</code> 。两个枚举间的枚举项数量不匹配—— <code>PaymentType</code> 有5个值，而 <code>PaymentTypeView</code> 只有3个。</p>
<p>为了在这些枚举项之间建立桥梁，我们可以使用<code>@ValueMappings</code>注解，该注解中可以包含多个<code>@ValueMapping</code>注解。这里，我们将<code>source</code>设置为三个具体枚举项之一，并将<code>target</code>设置为<code>CARD</code>。</p>
<p>MapStruct自然会处理这些情况：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PaymentTypeMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">PaymentTypeMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> PaymentTypeView <span class="token function">paymentTypeToPaymentTypeView</span><span class="token punctuation">(</span>PaymentType paymentType<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>paymentType <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        PaymentTypeView paymentTypeView<span class="token punctuation">;</span>

        <span class="token keyword">switch</span> <span class="token punctuation">(</span>paymentType<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">case</span> CARD_VISA<span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CARD<span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> CARD_MASTER<span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CARD<span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> CARD_CREDIT<span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CARD<span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> CASH<span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CASH<span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">case</span> CHEQUE<span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CHEQUE<span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token keyword">default</span><span class="token operator">:</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span> <span class="token string">"Unexpected enum constant: "</span> <span class="token operator">+</span> paymentType <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> paymentTypeView<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><code>CASH</code>和<code>CHEQUE</code>默认转换为对应值，特殊的 <code>CARD</code> 值通过<code>switch</code>循环处理。</p>
<p>但是，如果你要将很多值转换为一个更一般的值，这种方式就有些不切实际了。其实我们不必手动分配每一个值，只需要让MapStruct将所有剩余的可用枚举项（在目标枚举中找不到相同名称的枚举项），直接转换为对应的另一个枚举项。</p>
<p>可以通过 <code>MappingConstants</code>实现这一点：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@ValueMapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> MappingConstants<span class="token punctuation">.</span>ANY_REMAINING<span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"CARD"</span><span class="token punctuation">)</span>
PaymentTypeView <span class="token function">paymentTypeToPaymentTypeView</span><span class="token punctuation">(</span>PaymentType paymentType<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>在这个例子中，完成默认映射之后，所有剩余（未匹配）的枚举项都会映射为<code>CARD</code>：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> PaymentTypeView <span class="token function">paymentTypeToPaymentTypeView</span><span class="token punctuation">(</span>PaymentType paymentType<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span> paymentType <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> null<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    PaymentTypeView paymentTypeView<span class="token punctuation">;</span>

    <span class="token keyword">switch</span> <span class="token punctuation">(</span> paymentType <span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">case</span> CASH<span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CASH<span class="token punctuation">;</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token keyword">case</span> CHEQUE<span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CHEQUE<span class="token punctuation">;</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token keyword">default</span><span class="token operator">:</span> paymentTypeView <span class="token operator">=</span> PaymentTypeView<span class="token punctuation">.</span>CARD<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> paymentTypeView<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>还有一种选择是使用<code>ANY UNMAPPED</code>：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@ValueMapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> MappingConstants<span class="token punctuation">.</span>ANY_UNMAPPED<span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"CARD"</span><span class="token punctuation">)</span>
PaymentTypeView <span class="token function">paymentTypeToPaymentTypeView</span><span class="token punctuation">(</span>PaymentType paymentType<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>采用这种方式时，MapStruct不会像前面那样先处理默认映射，再将剩余的枚举项映射到<code>target</code>值。而是，直接将<em>所有</em>未通过<code>@ValueMapping</code>注解做显式映射的值都转换为<code>target</code>值。</p>
<h2 id="集合映射"><a href="#集合映射" class="headerlink" title="集合映射"></a>集合映射</h2><p>简单来说，使用MapStruct处理集合映射的方式与处理简单类型相同。</p>
<p>我们创建一个简单的接口或抽象类并声明映射方法。 MapStruct将根据我们的声明自动生成映射代码。 通常，生成的代码会遍历源集合，将每个元素转换为目标类型，并将每个转换后元素添加到目标集合中。</p>
<h3 id="List映射"><a href="#List映射" class="headerlink" title="List映射"></a>List映射</h3><p>我们先定义一个新的映射方法：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
    List<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> <span class="token function">map</span><span class="token punctuation">(</span>List<span class="token operator">&lt;</span>Doctor<span class="token operator">></span> doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>生成的代码大致如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> List<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> <span class="token function">map</span><span class="token punctuation">(</span>List<span class="token operator">&lt;</span>Doctor<span class="token operator">></span> doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> doctor <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        List<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span> Doctor doctor1 <span class="token operator">:</span> doctor <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span> <span class="token function">doctorToDoctorDto</span><span class="token punctuation">(</span> doctor1 <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> list<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">protected</span> DoctorDto <span class="token function">doctorToDoctorDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> doctor <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        DoctorDto doctorDto <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DoctorDto</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        doctorDto<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setSpecialization</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getSpecialization</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> doctorDto<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到，MapStruct为我们自动生成了从<code>Doctor</code>到<code>DoctorDto</code>的映射方法。</p>
<p>但是需要注意，如果我们在DTO中新增一个字段<code>fullName</code>，生成代码时会出现错误：</p>
<pre><code>警告: Unmapped target property: "fullName".</code></pre>
<p>基本上，这意味着MapStruct在当前情况下无法为我们自动生成映射方法。因此，我们需要手动定义<code>Doctor</code>和<code>DoctorDto</code>之间的映射方法。具体参考之前的小节。</p>
<h3 id="Set和Map映射"><a href="#Set和Map映射" class="headerlink" title="Set和Map映射"></a>Set和Map映射</h3><p>Set与Map型数据的处理方式与List相似。按照以下方式修改<code>DoctorMapper</code>：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    Set<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> <span class="token function">setConvert</span><span class="token punctuation">(</span>Set<span class="token operator">&lt;</span>Doctor<span class="token operator">></span> doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>

    Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> DoctorDto<span class="token operator">></span> <span class="token function">mapConvert</span><span class="token punctuation">(</span>Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> Doctor<span class="token operator">></span> doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>生成的最终实现代码如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> Set<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> <span class="token function">setConvert</span><span class="token punctuation">(</span>Set<span class="token operator">&lt;</span>Doctor<span class="token operator">></span> doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> doctor <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        Set<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> set <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashSet</span><span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span><span class="token punctuation">(</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token punctuation">.</span><span class="token number">75f</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">16</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span> Doctor doctor1 <span class="token operator">:</span> doctor <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            set<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span> <span class="token function">doctorToDoctorDto</span><span class="token punctuation">(</span> doctor1 <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> set<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> DoctorDto<span class="token operator">></span> <span class="token function">mapConvert</span><span class="token punctuation">(</span>Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> Doctor<span class="token operator">></span> doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> doctor <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        Map<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> DoctorDto<span class="token operator">></span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token operator">&lt;</span>String<span class="token punctuation">,</span> DoctorDto<span class="token operator">></span><span class="token punctuation">(</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token punctuation">.</span><span class="token number">75f</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">16</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">for</span> <span class="token punctuation">(</span> java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>Map<span class="token punctuation">.</span>Entry<span class="token operator">&lt;</span>String<span class="token punctuation">,</span> Doctor<span class="token operator">></span> entry <span class="token operator">:</span> doctor<span class="token punctuation">.</span><span class="token function">entrySet</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            String key <span class="token operator">=</span> entry<span class="token punctuation">.</span><span class="token function">getKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            DoctorDto value <span class="token operator">=</span> <span class="token function">doctorToDoctorDto</span><span class="token punctuation">(</span> entry<span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
            map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span> key<span class="token punctuation">,</span> value <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> map<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">protected</span> DoctorDto <span class="token function">doctorToDoctorDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> doctor <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        DoctorDto doctorDto <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DoctorDto</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        doctorDto<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setSpecialization</span><span class="token punctuation">(</span> doctor<span class="token punctuation">.</span><span class="token function">getSpecialization</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> doctorDto<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>与List映射类似，MapStruct自动生成了<code>Doctor</code>转换为<code>DoctorDto</code>的映射方法。</p>
<h3 id="集合映射策略"><a href="#集合映射策略" class="headerlink" title="集合映射策略"></a>集合映射策略</h3><p>很多场景中，我们需要对具有父子关系的数据类型进行转换。通常来说，会有一个数据类型（父），其字段是另一个数据类型（子）的集合。</p>
<p>对于这种情况，MapStruct提供了一种方法来选择如何将子类型设置或添加到父类型中。具体来说，就是<code>@Mapper </code>注解中的<code>collectionMappingStrategy</code>属性，该属性可以取值为<code>ACCESSOR_ONLY</code>， <code>SETTER_PREFERRED</code>， <code>ADDER_PREFERRED</code> 或<code>TARGET_IMMUTABLE</code>。</p>
<p>这些值分别表示不同的为子类型集合赋值的方式。默认值是<code>ACCESSOR_ONLY</code>，这意味着只能使用访问器来设置子集合。</p>
<p>当父类型中的<em>Collection</em>字段<code>setter</code>方法不可用，但我们有一个子类型<code>add</code>方法时，这个选项就派上用场了；另一种有用的情况是父类型中的<em>Collection</em>字段是不可变的。</p>
<p>我们新建一个类：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Hospital</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>Doctor<span class="token operator">></span> doctors<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<p>同时定义一个映射目标DTO类，同时定义子类型集合字段的getter、setter和adder：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">HospitalDto</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> doctors<span class="token punctuation">;</span>

        <span class="token comment" spellcheck="true">// 子类型集合字段getter</span>
    <span class="token keyword">public</span> List<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> <span class="token function">getDoctors</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> doctors<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
        <span class="token comment" spellcheck="true">// 子类型集合字段setter</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setDoctors</span><span class="token punctuation">(</span>List<span class="token operator">&lt;</span>DoctorDto<span class="token operator">></span> doctors<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>doctors <span class="token operator">=</span> doctors<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
        <span class="token comment" spellcheck="true">// 子类型数据adder</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addDoctor</span><span class="token punctuation">(</span>DoctorDto doctorDTO<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctors <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            doctors <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        doctors<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>doctorDTO<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>创建对应的映射器：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">HospitalMapper</span> <span class="token punctuation">{</span>
    HospitalMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>HospitalMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    HospitalDto <span class="token function">toDto</span><span class="token punctuation">(</span>Hospital hospital<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>生成的最终实现代码为：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">HospitalMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">HospitalMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> HospitalDto <span class="token function">toDto</span><span class="token punctuation">(</span>Hospital hospital<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> hospital <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        HospitalDto hospitalDto <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HospitalDto</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        hospitalDto<span class="token punctuation">.</span><span class="token function">setDoctors</span><span class="token punctuation">(</span> <span class="token function">doctorListToDoctorDtoList</span><span class="token punctuation">(</span> hospital<span class="token punctuation">.</span><span class="token function">getDoctors</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> hospitalDto<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到，在默认情况下采用的策略是<code>ACCESSOR_ONLY</code>，使用setter方法<code>setDoctors()</code>向<code>HospitalDto</code>对象中写入列表数据。</p>
<p>相对的，如果使用 <code>ADDER_PREFERRED</code> 作为映射策略：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>collectionMappingStrategy <span class="token operator">=</span> CollectionMappingStrategy<span class="token punctuation">.</span>ADDER_PREFERRED<span class="token punctuation">,</span>
        uses <span class="token operator">=</span> DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">HospitalMapper</span> <span class="token punctuation">{</span>
    HospitalMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>HospitalMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    HospitalDto <span class="token function">toDto</span><span class="token punctuation">(</span>Hospital hospital<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>此时，会使用adder方法逐个将转换后的子类型DTO对象加入父类型的集合字段中。</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CompanyMapperAdderPreferredImpl</span> <span class="token keyword">implements</span> <span class="token class-name">CompanyMapperAdderPreferred</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">final</span> EmployeeMapper employeeMapper <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span> EmployeeMapper<span class="token punctuation">.</span><span class="token keyword">class</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> CompanyDTO <span class="token function">map</span><span class="token punctuation">(</span>Company company<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> company <span class="token operator">==</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        CompanyDTO companyDTO <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CompanyDTO</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span> company<span class="token punctuation">.</span><span class="token function">getEmployees</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> null <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">for</span> <span class="token punctuation">(</span> Employee employee <span class="token operator">:</span> company<span class="token punctuation">.</span><span class="token function">getEmployees</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
                companyDTO<span class="token punctuation">.</span><span class="token function">addEmployee</span><span class="token punctuation">(</span> employeeMapper<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span> employee <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">return</span> companyDTO<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>如果目标DTO中既没有<code>setter</code>方法也没有<code>adder</code>方法，会先通过<code>getter</code>方法获取子类型集合，再调用集合的对应接口添加子类型对象。</p>
<p>可以在<a target="_blank" rel="noopener" href="https://mapstruct.org/documentation/stable/reference/html/#collection-mapping-strategies">参考文档</a>中看到不同类型的DTO定义（是否包含setter方法或adder方法），采用不同的映射策略时，所使用的添加子类型到集合中的方式。</p>
<h3 id="目标集合实现类型"><a href="#目标集合实现类型" class="headerlink" title="目标集合实现类型"></a>目标集合实现类型</h3><p>MapStruct支持将集合接口作为映射方法的目标类型。</p>
<p>在这种情况下，在生成的代码中会使用一些集合接口默认实现。 例如，上面的示例中，<code>List</code>的默认实现是<code>ArrayList</code>。</p>
<p>常见接口及其对应的默认实现如下：</p>
<table>
<thead>
<tr>
<th align="left">Interface type</th>
<th align="left">Implementation type</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><code>Collection</code></td>
<td align="left"><code>ArrayList</code></td>
</tr>
<tr>
<td align="left"><code>List</code></td>
<td align="left"><code>ArrayList</code></td>
</tr>
<tr>
<td align="left"><code>Map</code></td>
<td align="left"><code>HashMap</code></td>
</tr>
<tr>
<td align="left"><code>SortedMap</code></td>
<td align="left"><code>TreeMap</code></td>
</tr>
<tr>
<td align="left"><code>ConcurrentMap</code></td>
<td align="left"><code>ConcurrentHashMap</code></td>
</tr>
</tbody></table>
<p>你可以在<a target="_blank" rel="noopener" href="https://mapstruct.org/documentation/stable/reference/html/#implementation-types-for-collection-mappings">参考文档</a>中找到MapStruct支持的所有接口列表，以及每个接口对应的默认实现类型。</p>
<h1 id="进阶操作"><a href="#进阶操作" class="headerlink" title="进阶操作"></a>进阶操作</h1><h2 id="依赖注入"><a href="#依赖注入" class="headerlink" title="依赖注入"></a>依赖注入</h2><p>到目前为止，我们一直在通过<code>getMapper()</code>方法访问生成的映射器：</p>
<pre class=" language-java"><code class="language-java">DoctorMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>但是，如果你使用的是Spring，只需要简单修改映射器配置，就可以像常规依赖项一样注入映射器。</p>
<p>修改 <code>DoctorMapper</code> 以支持Spring框架：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
<p>在<code>@Mapper</code>注解中添加<code>（componentModel = "spring"）</code>，是为了告诉MapStruct，在生成映射器实现类时，我们希望它能支持通过Spring的依赖注入来创建。现在，就不需要在接口中添加 <code>INSTANCE</code> 字段了。</p>
<p>这次生成的 <code>DoctorMapperImpl</code> 会带有 <code>@Component</code> 注解：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
<p>只要被标记为<code>@Component</code>，Spring就可以把它作为一个bean来处理，你就可以在其它类（如控制器）中通过<code>@Autowire</code>注解来使用它：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Controller</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorController</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> DoctorMapper doctorMapper<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>如果你不使用Spring, MapStruct也支持<a target="_blank" rel="noopener" href="https://docs.oracle.com/javaee/6/tutorial/doc/giwhl.html">Java CDI</a>：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>componentModel <span class="token operator">=</span> <span class="token string">"cdi"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
<h2 id="添加默认值"><a href="#添加默认值" class="headerlink" title="添加默认值"></a>添加默认值</h2><p> <code>@Mapping</code> 注解有两个很实用的标志就是常量 <code>constant</code> 和默认值 <code>defaultValue</code> 。无论<code>source</code>如何取值，都将始终使用常量值； 如果<code>source</code>取值为<code>null</code>，则会使用默认值。</p>
<p>修改一下 <code>DoctorMapper</code> ，添加一个 <code>constant</code> 和一个 <code>defaultValue</code> ：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">,</span> componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>target <span class="token operator">=</span> <span class="token string">"id"</span><span class="token punctuation">,</span> constant <span class="token operator">=</span> <span class="token string">"-1"</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.patientList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientDtoList"</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.specialty"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialization"</span><span class="token punctuation">,</span> defaultValue <span class="token operator">=</span> <span class="token string">"Information Not Available"</span><span class="token punctuation">)</span>
    DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>如果<code>specialty</code>不可用，我们会替换为<code>"Information Not Available"</code>字符串，此外，我们将<code>id</code>硬编码为<code>-1</code>。</p>
<p>生成代码如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> PatientMapper patientMapper<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctor <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        DoctorDto doctorDto <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DoctorDto</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getSpecialty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            doctorDto<span class="token punctuation">.</span><span class="token function">setSpecialization</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getSpecialty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span> <span class="token punctuation">{</span>
            doctorDto<span class="token punctuation">.</span><span class="token function">setSpecialization</span><span class="token punctuation">(</span><span class="token string">"Information Not Available"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setPatientDtoList</span><span class="token punctuation">(</span><span class="token function">patientListToPatientDtoList</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        doctorDto<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> doctorDto<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到，如果 <code>doctor.getSpecialty()</code> 返回值为<code>null</code>，则将<code>specialization</code>设置为我们的默认信息。无论任何情况，都会对 <code>id</code>赋值，因为这是一个<code>constant</code>。</p>
<h2 id="添加表达式"><a href="#添加表达式" class="headerlink" title="添加表达式"></a>添加表达式</h2><p>MapStruct甚至允许在<code>@Mapping</code>注解中输入Java表达式。你可以设置 <code>defaultExpression</code> （ <code>source</code> 取值为 <code>null</code>时生效），或者一个<code>expression</code>（类似常量，永久生效）。</p>
<p>在 <code>Doctor</code> 和 <code>DoctorDto</code>两个类中都加了两个新属性，一个是 <code>String</code> 类型的 <code>externalId</code> ，另一个是<code>LocalDateTime</code>类型的 <code>appointment</code> ，两个类大致如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Doctor</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String externalId<span class="token punctuation">;</span>
    <span class="token keyword">private</span> String specialty<span class="token punctuation">;</span>
    <span class="token keyword">private</span> LocalDateTime availability<span class="token punctuation">;</span>
    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>Patient<span class="token operator">></span> patientList<span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// getters and setters or builder</span>
<span class="token punctuation">}</span></code></pre>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorDto</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>    <span class="token keyword">private</span> String name<span class="token punctuation">;</span>    <span class="token keyword">private</span> String externalId<span class="token punctuation">;</span>    <span class="token keyword">private</span> String specialization<span class="token punctuation">;</span>    <span class="token keyword">private</span> LocalDateTime availability<span class="token punctuation">;</span>    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>PatientDto<span class="token operator">></span> patientDtoList<span class="token punctuation">;</span>    <span class="token comment" spellcheck="true">// getters and setters or builder}</span></code></pre>
<p>修改 <code>DoctorMapper</code>：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">,</span> componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">,</span> imports <span class="token operator">=</span> <span class="token punctuation">{</span>LocalDateTime<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> UUID<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>target <span class="token operator">=</span> <span class="token string">"externalId"</span><span class="token punctuation">,</span> expression <span class="token operator">=</span> <span class="token string">"java(UUID.randomUUID().toString())"</span><span class="token punctuation">)</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.availability"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"availability"</span><span class="token punctuation">,</span> defaultExpression <span class="token operator">=</span> <span class="token string">"java(LocalDateTime.now())"</span><span class="token punctuation">)</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.patientList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientDtoList"</span><span class="token punctuation">)</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.specialty"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialization"</span><span class="token punctuation">)</span>    DoctorDto <span class="token function">toDtoWithExpression</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre>
<p>可以看到，这里将 <code>externalId</code>的值设置为 <code>java(UUID.randomUUID().toString())</code> ，如果源对象中没有 <code>availability</code> 属性，则会把目标对象中的 <code>availability</code> 设置为一个新的 <code>LocalDateTime</code>对象。</p>
<p>由于表达式只是字符串，我们必须在表达式中指定使用的类。但是这里的表达式并不是最终执行的代码，只是一个字母的文本值。因此，我们要在 <code>@Mapper</code> 中添加 <code>imports = {LocalDateTime.class, UUID.class}</code> 。</p>
<h2 id="添加自定义方法"><a href="#添加自定义方法" class="headerlink" title="添加自定义方法"></a>添加自定义方法</h2><p>到目前为止，我们一直使用的策略是添加一个“占位符”方法，并期望MapStruct能为我们实现它。其实我们还可以向接口中添加自定义的<code>default</code>方法，也可以通过<code>default</code>方法直接实现一个映射。然后我们可以通过实例直接调用该方法，没有任何问题。</p>
<p>为此，我们创建一个 <code>DoctorPatientSummary</code>类，其中包含一个 <code>Doctor</code> 及其 <code>Patient</code>列表的汇总信息：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorPatientSummary</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">int</span> doctorId<span class="token punctuation">;</span>    <span class="token keyword">private</span> <span class="token keyword">int</span> patientCount<span class="token punctuation">;</span>    <span class="token keyword">private</span> String doctorName<span class="token punctuation">;</span>    <span class="token keyword">private</span> String specialization<span class="token punctuation">;</span>    <span class="token keyword">private</span> String institute<span class="token punctuation">;</span>    <span class="token keyword">private</span> List<span class="token operator">&lt;</span>Integer<span class="token operator">></span> patientIds<span class="token punctuation">;</span>    <span class="token comment" spellcheck="true">// getters and setters or builder}</span></code></pre>
<p>接下来，我们在 <code>DoctorMapper</code>中添加一个<code>default</code>方法，该方法会将 <code>Doctor</code> 和 <code>Education</code> 对象转换为一个 <code>DoctorPatientSummary</code>:</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    <span class="token keyword">default</span> DoctorPatientSummary <span class="token function">toDoctorPatientSummary</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">,</span> Education education<span class="token punctuation">)</span> <span class="token punctuation">{</span>

        <span class="token keyword">return</span> DoctorPatientSummary<span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">doctorId</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">doctorName</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">patientCount</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                                <span class="token punctuation">.</span><span class="token function">patientIds</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                        <span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                      <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Patient<span class="token operator">:</span><span class="token operator">:</span>getId<span class="token punctuation">)</span>
                        <span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span>Collectors<span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">institute</span><span class="token punctuation">(</span>education<span class="token punctuation">.</span><span class="token function">getInstitute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">specialization</span><span class="token punctuation">(</span>education<span class="token punctuation">.</span><span class="token function">getDegreeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>这里使用了Builder模式创建<code>DoctorPatientSummary</code>对象。</p>
<p>在MapStruct生成映射器实现类之后，你就可以使用这个实现方法，就像访问任何其它映射器方法一样：</p>
<pre class=" language-java"><code class="language-java">DoctorPatientSummary summary <span class="token operator">=</span> doctorMapper<span class="token punctuation">.</span><span class="token function">toDoctorPatientSummary</span><span class="token punctuation">(</span>dotor<span class="token punctuation">,</span> education<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="创建自定义映射器"><a href="#创建自定义映射器" class="headerlink" title="创建自定义映射器"></a>创建自定义映射器</h2><p>前面我们一直是通过接口来设计映射器功能，其实我们也可以通过一个带 <code>@Mapper</code> 的 <code>abstract</code> 类来实现一个映射器。MapStruct也会为这个类创建一个实现，类似于创建一个接口实现。</p>
<p>我们重写一下前面的示例，这一次，我们将它修改为一个抽象类：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
<span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">DoctorCustomMapper</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> DoctorPatientSummary <span class="token function">toDoctorPatientSummary</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">,</span> Education education<span class="token punctuation">)</span> <span class="token punctuation">{</span>

        <span class="token keyword">return</span> DoctorPatientSummary<span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">doctorId</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">doctorName</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">patientCount</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">patientIds</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                        <span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                        <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Patient<span class="token operator">:</span><span class="token operator">:</span>getId<span class="token punctuation">)</span>
                        <span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span>Collectors<span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">institute</span><span class="token punctuation">(</span>education<span class="token punctuation">.</span><span class="token function">getInstitute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">specialization</span><span class="token punctuation">(</span>education<span class="token punctuation">.</span><span class="token function">getDegreeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
                <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>你可以用同样的方式使用这个映射器。由于限制较少，使用抽象类可以在创建自定义实现时给我们更多的控制和选择。另一个好处是可以添加<code>@BeforeMapping</code>和<code>@AfterMapping</code>方法。</p>
<h3 id="BeforeMapping-和-AfterMapping"><a href="#BeforeMapping-和-AfterMapping" class="headerlink" title="@BeforeMapping 和 @AfterMapping"></a>@BeforeMapping 和 @AfterMapping</h3><p>为了进一步控制和定制化，我们可以定义 <code>@BeforeMapping</code> 和 <code>@AfterMapping</code>方法。显然，这两个方法是在每次映射之前和之后执行的。也就是说，在最终的实现代码中，会在两个对象真正映射之前和之后添加并执行这两个方法。</p>
<p>可以在 <code>DoctorCustomMapper</code>中添加两个方法：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">,</span> componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">DoctorCustomMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@BeforeMapping</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">validate</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> null<span class="token punctuation">)</span><span class="token punctuation">{</span>
            doctor<span class="token punctuation">.</span><span class="token function">setPatientList</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@AfterMapping</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">updateResult</span><span class="token punctuation">(</span><span class="token annotation punctuation">@MappingTarget</span> DoctorDto doctorDto<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setDegree</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getDegree</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setSpecialization</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">.</span><span class="token function">getSpecialization</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.patientList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientDtoList"</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.specialty"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialization"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">abstract</span> DoctorDto <span class="token function">toDoctorDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>基于该抽象类生成一个映射器实现类：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DoctorCustomMapperImpl</span> <span class="token keyword">extends</span> <span class="token class-name">DoctorCustomMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> PatientMapper patientMapper<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> DoctorDto <span class="token function">toDoctorDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">validate</span><span class="token punctuation">(</span>doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctor <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> null<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        DoctorDto doctorDto <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DoctorDto</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        doctorDto<span class="token punctuation">.</span><span class="token function">setPatientDtoList</span><span class="token punctuation">(</span><span class="token function">patientListToPatientDtoList</span><span class="token punctuation">(</span>doctor
            <span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setSpecialization</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getSpecialty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        doctorDto<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token function">updateResult</span><span class="token punctuation">(</span>doctorDto<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> doctorDto<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到， <code>validate()</code> 方法会在 <code>DoctorDto</code> 对象实例化之前执行，而<code>updateResult()</code>方法会在映射结束之后执行。</p>
<h2 id="映射异常处理"><a href="#映射异常处理" class="headerlink" title="映射异常处理"></a>映射异常处理</h2><p>异常处理是不可避免的，应用程序随时会产生异常状态。MapStruct提供了对异常处理的支持，可以简化开发者的工作。</p>
<p>考虑这样一个场景，我们想在 <code>Doctor</code> 映射为<code>DoctorDto</code>之前校验一下 <code>Doctor</code> 的数据。我们新建一个独立的 <code>Validator</code> 类进行校验：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Validator</span> <span class="token punctuation">{</span>    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">validateId</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">)</span> <span class="token keyword">throws</span> ValidationException <span class="token punctuation">{</span>        <span class="token keyword">if</span><span class="token punctuation">(</span>id <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">{</span>            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ValidationException</span><span class="token punctuation">(</span><span class="token string">"Invalid value in ID"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>        <span class="token keyword">return</span> id<span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre>
<p>我们修改一下 <code>DoctorMapper</code> 以使用 <code>Validator</code> 类，无需指定实现。跟之前一样， 在<code>@Mapper</code>使用的类列表中添加该类。我们还需要做的就是告诉MapStruct我们的 <code>toDto()</code> 会抛出 <code>throws ValidationException</code>：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> Validator<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">,</span> componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.patientList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientDtoList"</span><span class="token punctuation">)</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctor.specialty"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialization"</span><span class="token punctuation">)</span>    DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token keyword">throws</span> ValidationException<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre>
<p>最终生成的映射器代码如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Componentpublic</span> <span class="token keyword">class</span> <span class="token class-name">DoctorMapperImpl</span> <span class="token keyword">implements</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Autowired</span>    <span class="token keyword">private</span> PatientMapper patientMapper<span class="token punctuation">;</span>    <span class="token annotation punctuation">@Autowired</span>    <span class="token keyword">private</span> Validator validator<span class="token punctuation">;</span>    <span class="token annotation punctuation">@Override</span>    <span class="token keyword">public</span> DoctorDto <span class="token function">toDto</span><span class="token punctuation">(</span>Doctor doctor<span class="token punctuation">)</span> <span class="token keyword">throws</span> ValidationException <span class="token punctuation">{</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>doctor <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token keyword">return</span> null<span class="token punctuation">;</span>        <span class="token punctuation">}</span>        DoctorDto doctorDto <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DoctorDto</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        doctorDto<span class="token punctuation">.</span><span class="token function">setPatientDtoList</span><span class="token punctuation">(</span><span class="token function">patientListToPatientDtoList</span><span class="token punctuation">(</span>doctor            <span class="token punctuation">.</span><span class="token function">getPatientList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        doctorDto<span class="token punctuation">.</span><span class="token function">setSpecialization</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getSpecialty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        doctorDto<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>validator<span class="token punctuation">.</span><span class="token function">validateId</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        doctorDto<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        doctorDto<span class="token punctuation">.</span><span class="token function">setExternalId</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getExternalId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        doctorDto<span class="token punctuation">.</span><span class="token function">setAvailability</span><span class="token punctuation">(</span>doctor<span class="token punctuation">.</span><span class="token function">getAvailability</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">return</span> doctorDto<span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre>
<p>MapStruct自动将<code>doctorDto</code>的<code>id</code>设置为<code>Validator</code>实例的方法返回值。它还在该方法签名中添加了一个throws子句。</p>
<p>注意，如果映射前后的一对属性的类型与<code>Validator</code>中的方法出入参类型一致，那该字段映射时就会调用<code>Validator</code>中的方法，所以该方式请谨慎使用。</p>
<h2 id="映射配置"><a href="#映射配置" class="headerlink" title="映射配置"></a>映射配置</h2><p>MapStruct为编写映射器方法提供了一些非常有用的配置。多数情况下，如果我们已经定义了两个类型之间的映射方法，当我们要添加相同类型之间的另一个映射方法时，我们往往会直接复制已有方法的映射配置。</p>
<p>其实我们不必手动复制这些注解，只需要简单的配置就可以创建一个相同/相似的映射方法。</p>
<h3 id="继承配置"><a href="#继承配置" class="headerlink" title="继承配置"></a>继承配置</h3><p>我们回顾一下“<a href="#%E6%9B%B4%E6%96%B0%E7%8E%B0%E6%9C%89%E5%AE%9E%E4%BE%8B">更新现有实例</a>”，在该场景中，我们创建了一个映射器，根据DoctorDto对象的属性更新现有的Doctor对象的属性值：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>    DoctorMapper INSTANCE <span class="token operator">=</span> Mappers<span class="token punctuation">.</span><span class="token function">getMapper</span><span class="token punctuation">(</span>DoctorMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.patientDtoList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientList"</span><span class="token punctuation">)</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.specialization"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialty"</span><span class="token punctuation">)</span>    <span class="token keyword">void</span> <span class="token function">updateModel</span><span class="token punctuation">(</span>DoctorDto doctorDto<span class="token punctuation">,</span> <span class="token annotation punctuation">@MappingTarget</span> Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre>
<p>假设我们还有另一个映射器，将 <code>DoctorDto</code>转换为 <code>Doctor</code> ：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> Validator<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.patientDtoList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientList"</span><span class="token punctuation">)</span>    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.specialization"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialty"</span><span class="token punctuation">)</span>    Doctor <span class="token function">toModel</span><span class="token punctuation">(</span>DoctorDto doctorDto<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre>
<p>这两个映射方法使用了相同的注解配置， <code>source</code>和 <code>target</code>都是相同的。其实我们可以使用<code>@InheritConfiguration</code>注释，从而避免这两个映射器方法的重复配置。</p>
<p>如果对一个方法添加 <code>@InheritConfiguration</code> 注解，MapStruct会检索其它的已配置方法，寻找可用于当前方法的注解配置。一般来说，这个注解都用于<code>mapping</code>方法后面的<code>update</code>方法，如下所示：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>uses <span class="token operator">=</span> <span class="token punctuation">{</span>PatientMapper<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> Validator<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">,</span> componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">DoctorMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.specialization"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"specialty"</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"doctorDto.patientDtoList"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"patientList"</span><span class="token punctuation">)</span>
    Doctor <span class="token function">toModel</span><span class="token punctuation">(</span>DoctorDto doctorDto<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@InheritConfiguration</span>
    <span class="token keyword">void</span> <span class="token function">updateModel</span><span class="token punctuation">(</span>DoctorDto doctorDto<span class="token punctuation">,</span> <span class="token annotation punctuation">@MappingTarget</span> Doctor doctor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="继承逆向配置"><a href="#继承逆向配置" class="headerlink" title="继承逆向配置"></a>继承逆向配置</h3><p>还有另外一个类似的场景，就是编写映射函数将*<strong>Model*** 转为 *</strong>DTO*<strong>，以及将 **<em>DTO</em></strong> 转为 <strong><em>Model</em></strong>。如下面的代码所示，我们必须在两个函数上添加相同的注释。</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">PatientMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> dateFormat <span class="token operator">=</span> <span class="token string">"dd/MMM/yyyy"</span><span class="token punctuation">)</span>
    Patient <span class="token function">toModel</span><span class="token punctuation">(</span>PatientDto patientDto<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> dateFormat <span class="token operator">=</span> <span class="token string">"dd/MMM/yyyy"</span><span class="token punctuation">)</span>
    PatientDto <span class="token function">toDto</span><span class="token punctuation">(</span>Patient patient<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>两个方法的配置不会是完全相同的，实际上，它们应该是相反的。将*<strong>Model*** 转为 *</strong>DTO*<strong>，以及将 **<em>DTO</em></strong> 转为 <strong><em>Model</em></strong>——映射前后的字段相同，但是源属性字段与目标属性字段是相反的。</p>
<p>我们可以在第二个方法上使用<code>@InheritInverseConfiguration</code>注解，避免写两遍映射配置：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span><span class="token punctuation">(</span>componentModel <span class="token operator">=</span> <span class="token string">"spring"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">PatientMapper</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Mapping</span><span class="token punctuation">(</span>source <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> target <span class="token operator">=</span> <span class="token string">"dateOfBirth"</span><span class="token punctuation">,</span> dateFormat <span class="token operator">=</span> <span class="token string">"dd/MMM/yyyy"</span><span class="token punctuation">)</span>
    Patient <span class="token function">toModel</span><span class="token punctuation">(</span>PatientDto patientDto<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@InheritInverseConfiguration</span>
    PatientDto <span class="token function">toDto</span><span class="token punctuation">(</span>Patient patient<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>这两个Mapper生成的代码是相同的。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>在本文中，我们探讨了MapStruct——一个用于创建映射器类的库。从基本映射到自定义方法和自定义映射器，此外， 我们还介绍了MapStruct提供的一些高级操作选项，包括依赖注入，数据类型映射、枚举映射和表达式使用。</p>
<p>MapStruct提供了一个功能强大的集成插件，可减少开发人员编写模板代码的工作量，使创建映射器的过程变得简单快捷。</p>
<p>如果要探索更多、更详细的使用方式，可以参考MapStruct官方提供的<a target="_blank" rel="noopener" href="https://mapstruct.org/documentation/stable/reference/html/">参考指南</a>。</p>
<hr>
<p>欢迎关注公众号：<strong>码道诚公</strong></p>
<p><img src="/posts/b23f3fc/qrcode_for_gh_bcb15cafda77_258.jpeg" alt="码道诚公"></p>

            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/about" rel="external nofollow noreferrer">Guo Yaxiang</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://www.codinghonest.space/posts/b23f3fc.html">https://www.codinghonest.space/posts/b23f3fc.html</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/about" target="_blank">Guo Yaxiang</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/tags/Java/">
                                    <span class="chip bg-color">Java</span>
                                </a>
                            
                                <a href="/tags/%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7/">
                                    <span class="chip bg-color">效率工具</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/medias/reward/alipay.png" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    

    

    
        <style>
    .mvaline-card {
        margin: 1.5rem auto;
    }

    .mvaline-card .card-content {
        padding: 20px 20px 5px 20px;
    }
</style>

<div class="card mvaline-card" data-aos="fade-up">
    <div class="comment_headling" style="font-size: 20px; font-weight: 700; position: relative; padding-left: 20px; top: 15px; padding-bottom: 5px;">
        <i class="fas fa-comments fa-fw" aria-hidden="true"></i>
        <span>评论</span>
    </div>
    <div id="mvcomments" class="card-content" style="display: grid">
    </div>
</div>

<script src="/libs/minivaline/MiniValine.js"></script>
<script>
    new MiniValine({
        el: '#mvcomments',
        appId: 'oqAo7rCWejwTqHjGC2APTVDX-MdYXbMMI',
        appKey: 'pfyY919tO7iJaDm7lFmvh5Wp',
        mode: 'DesertsP',
        placeholder: 'Write a Comment',
        pathname: window.location.pathname,
        lang: '',
        adminEmailMd5: '8BBC105436DAAF8C803841C8FD13CD0C',
        tagMeta: ["管理员", "小伙伴", "访客"],
        master: ["8BBC105436DAAF8C803841C8FD13CD0C"],
        friends: ["FA21C7921CD42FE9523E957870873F64", "586BAB41BB5692877F7714DFE4947DEC"],
        math: true,
        md: true,
        enableQQ: false,
        NoRecordIP: false,
        visitor: true,
        maxNest: 6,
        pageSize: 6,
        serverURLs: '',
        emoticonUrl: ["https://cdn.jsdelivr.net/npm/alus@latest", "https://cdn.jsdelivr.net/gh/MiniValine/qq@latest", "https://cdn.jsdelivr.net/gh/MiniValine/Bilibilis@latest", "https://cdn.jsdelivr.net/gh/MiniValine/tieba@latest", "https://cdn.jsdelivr.net/gh/MiniValine/twemoji@latest", "https://cdn.jsdelivr.net/gh/MiniValine/weibo@latest"],
    });
</script>

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/posts/4a84ab11.html">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/14.jpg" class="responsive-img" alt="【译】从OOP到函数式">
                        
                        <span class="card-title">【译】从OOP到函数式</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            在本文中，将尝试分解一下概念，并回答在从OOP切换FP时会带来困扰的常见问题。
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2021-08-24
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/%E5%87%BD%E6%95%B0%E5%BC%8F/" class="post-category">
                                    函数式
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/%E5%87%BD%E6%95%B0%E5%BC%8F/">
                        <span class="chip bg-color">函数式</span>
                    </a>
                    
                    <a href="/tags/%E8%AF%91%E6%96%87/">
                        <span class="chip bg-color">译文</span>
                    </a>
                    
                    <a href="/tags/Scala/">
                        <span class="chip bg-color">Scala</span>
                    </a>
                    
                    <a href="/tags/Haskell/">
                        <span class="chip bg-color">Haskell</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/posts/dc1362d2.html">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/14.jpg" class="responsive-img" alt="响应式系统中的背压">
                        
                        <span class="card-title">响应式系统中的背压</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            这篇文章是关于反压力的简单介绍，并讲述了RxJava (v3)、Project Reactor和Kotlin的协程中是如何处理它的。
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-04-20
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/Java/" class="post-category">
                                    Java
                                </a>
                            
                            <a href="/categories/Java/Reactive-Stream/" class="post-category">
                                    Reactive Stream
                                </a>
                            
                            <a href="/categories/Java/Reactive-Stream/%E5%93%8D%E5%BA%94%E5%BC%8F/" class="post-category">
                                    响应式
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/Java-Stream/">
                        <span class="chip bg-color">Java Stream</span>
                    </a>
                    
                    <a href="/tags/Reactive-Stream/">
                        <span class="chip bg-color">Reactive Stream</span>
                    </a>
                    
                    <a href="/tags/%E5%93%8D%E5%BA%94%E5%BC%8F%E7%BC%96%E7%A8%8B/">
                        <span class="chip bg-color">响应式编程</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>


<script>
    $('#articleContent').on('copy', function (e) {
        // IE8 or earlier browser is 'undefined'
        if (typeof window.getSelection === 'undefined') return;

        var selection = window.getSelection();
        // if the selection is short let's not annoy our users.
        if (('' + selection).length < Number.parseInt('120')) {
            return;
        }

        // create a div outside of the visible area and fill it with the selected text.
        var bodyElement = document.getElementsByTagName('body')[0];
        var newdiv = document.createElement('div');
        newdiv.style.position = 'absolute';
        newdiv.style.left = '-99999px';
        bodyElement.appendChild(newdiv);
        newdiv.appendChild(selection.getRangeAt(0).cloneContents());

        // we need a <pre> tag workaround.
        // otherwise the text inside "pre" loses all the line breaks!
        if (selection.getRangeAt(0).commonAncestorContainer.nodeName === 'PRE') {
            newdiv.innerHTML = "<pre>" + newdiv.innerHTML + "</pre>";
        }

        var url = document.location.href;
        newdiv.innerHTML += '<br />'
            + '来源: 码道诚公<br />'
            + '文章作者: Guo Yaxiang<br />'
            + '文章链接: <a href="' + url + '">' + url + '</a><br />'
            + '本文章著作权归作者所有，任何形式的转载都请注明出处。';

        selection.selectAllChildren(newdiv);
        window.setTimeout(function () {bodyElement.removeChild(newdiv);}, 200);
    });
</script>


<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/libs/codeBlock/codeShrink.js"></script>


<!-- 代码块折行 -->

<style type="text/css">
code[class*="language-"], pre[class*="language-"] { white-space: pre !important; }
</style>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="503838841"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    
    <div class="container row center-align" style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2020-2021</span>
            
            <span id="year">2020</span>
            <a href="/about" target="_blank">Guo Yaxiang</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
            
            
            
            
            <br>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link ">
    <a href="https://github.com/GuoYaxiang" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:YXGyxg112358@163.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=1431800679" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 1431800679" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>





    <a href="https://www.zhihu.com/people/guo-ya-xiang" class="tooltipped" target="_blank" data-tooltip="关注我的知乎: https://www.zhihu.com/people/guo-ya-xiang" data-position="top" data-delay="50">
        <i class="fab fa-zhihu1">知</i>
    </a>



    <a href="/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script src="/js/search.js"></script>
<script type="text/javascript">
$(function () {
    searchFunc('/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/libs/materialize/materialize.min.js"></script>
    <script src="/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/libs/aos/aos.js"></script>
    <script src="/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/libs/others/clicklove.js" async="async"></script>
    
    

    
        <script src="//code.tidio.co/zgiqinzrat1rzwxseqhr2pnzsp2a4rjo.js"></script>
        <script>
            $(document).ready(function () {
                setInterval(change_Tidio, 50);
                function change_Tidio() {
                    var tidio=$("#tidio-chat iframe");
                    if(tidio.css("display")=="block"&& $(window).width()>977 ){
                        document.getElementById("tidio-chat-iframe").style.bottom= ($("div#backTop.top-scroll").css("display")=="none" &&$(window).width()>977)>0? "-40px" : ($("div.toc-title").length&&$(window).width()>977)>0?"85px":"20px";
                        document.getElementById("tidio-chat-iframe").style.right="-15px";
                        document.getElementById("tidio-chat-iframe").style.height=parseInt(tidio.css("height"))>=520?"520px":tidio.css("height");
                        document.getElementById("tidio-chat-iframe").style.zIndex="997";
                    }
                    else if(tidio.css("display")=="block"&&$(window).width()>601 &&$(window).width()<992 ){
                        document.getElementById("tidio-chat-iframe").style.bottom= ($("div#backTop.top-scroll").css("display")=="none" && 601< $(window).width()<992)>0? "-40px":"20px" ;
                        document.getElementById("tidio-chat-iframe").style.right="-15px";
                        document.getElementById("tidio-chat-iframe").style.zIndex="997";
                    }
                    else if(tidio.css("display")=="block"&&$(window).width()<601 && parseInt(tidio.css("height"))<230){
                        document.getElementById("tidio-chat-iframe").style.bottom= ($("div#backTop.top-scroll").css("display")=="none" && $(window).width()<601)>0? "-10px":"45px" ;
                        document.getElementById("tidio-chat-iframe").style.zIndex="997";
                    }
                    if( tidio.css("display")=="block"&&$(window).width()<601 && parseInt(tidio.css("height"))>=230){
                        document.getElementById("tidio-chat-iframe").style.zIndex="998";
                    }
                }
            });
        </script>
    

    

    

    

    

    
    <script src="/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
